package tests;

import static org.junit.Assert.*;
import graphNew.DinicMainGraph;
import graphNew.FlowingEdge;
import graphNew.MainGraph;

import java.util.HashSet;
import java.util.Set;
import java.util.Vector;

import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import components.Goal;
import components.Operator;
import components.PrePostCond;
import components.PrevailCond;
import components.Variable;

public class DinicMainGraphTest {
	
	Vector<Goal> gs=new Vector<Goal>();
	DefaultDirectedWeightedGraph<Operator,FlowingEdge> g2;
	DefaultDirectedWeightedGraph<Operator,FlowingEdge> g3;
	DinicMainGraph g;
	MainGraph mg;
	Operator v5;
	Operator v4;
	Operator o1;
	Operator o2;

	@Before
	public void setUp() throws Exception {
		Variable v1=new Variable("v1", 5, -1, 0);
		Variable v2=new Variable("v2", 5, -1, 1);
		Variable v3=new Variable("v3", 5, -1, 2);
		try {
			v1.setState(1);
			v2.setState(0);
			v3.setState(0);
		
			PrePostCond p1=new PrePostCond(v3, 0, 4);
			PrePostCond p2=new PrePostCond(v2, 0, 3);
			PrePostCond p3=new PrePostCond(v1, 1, 2);
			PrePostCond p4=new PrePostCond(v3, 0, 5);
			PrevailCond pv=new PrevailCond(v1, 1);
			PrevailCond pv2=new PrevailCond(v2, 0);
			Vector<PrePostCond> prep1= new Vector<PrePostCond>();
			prep1.add(p1);
			prep1.add(p2);
			prep1.add(p3);
			Vector<PrePostCond> prep2= new Vector<PrePostCond>();
			Vector<PrevailCond> prev = new Vector<PrevailCond>();
			prev.add(pv);
			prev.add(pv2);
			
			
			
			o1= new Operator("o1",prep1 , new Vector<PrevailCond>(),1);
			o2= new Operator("o2",prep2 , prev,1);
			
			Vector<Operator> op=new Vector<Operator>();
			op.add(o1);
			op.add(o2);

			Goal g=new Goal(v2, 3);
			gs.add(g);
			
			mg=new MainGraph(op);
			
			
			
			
			
			g2= new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
			g2.addVertex(o1);
			g2.addVertex(o2);
			FlowingEdge e=g2.addEdge(o1, o2);
			e.setCapacity(5);
			e.setFlow(3);
			
			
			
			g3=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
			v5 = new Operator("v1");
			Operator v6 = new Operator("v2");
			Operator v7 = new Operator("v3");
			v4 = new Operator("v4");
			g3.addVertex(v5);
			g3.addVertex(v6);
			g3.addVertex(v7);
			g3.addVertex(v4);
			e=g3.addEdge(v5, v6);
			e.setCapacity(1);
			e=g3.addEdge(v6, v7);
			e.setCapacity(10);
			e.setFlow(10);
			e=g3.addEdge(v5, v7);
			e.setCapacity(1);
			e=g3.addEdge(v6, v4);
			e.setCapacity(1);
			e=g3.addEdge(v7, v4);
			e.setCapacity(1);
			
			
			
			
			
		}catch (Exception ex) {
			System.out.println("exception in before");
		}
		
		
		
		
		
		

	}

	@After
	public void tearDown() throws Exception {
	}
	
	

	
	
	
	
	
	
	
	
	
	
	
	@Test
	public void testDinicMainGraph() {
		try {
			g=new DinicMainGraph(gs,mg);
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");
			
		}
		//System.out.println(g);
		assertTrue("number of edges",g.getMaingraph().edgeSet().size()==4);
		assertTrue("number of verteces",g.getMaingraph().vertexSet().size()==4);
	}


	@Test
	public void testGetResidualNetwork() {
		try {
			g=new DinicMainGraph(gs,mg);
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");
			
		}
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> test=g.getResidualNetwork(g2);
		assertTrue("number of vertexes",test.vertexSet().size()==2);
		assertTrue("number of edges",test.edgeSet().size()==2);
		
		
		test=g.getResidualNetwork(g3);
		assertTrue("number of vertexes",test.vertexSet().size()==4);
		assertTrue("number of edges",test.edgeSet().size()==5);
		
	}


	@Test
	public void testGetBottleN() {
		Vector<FlowingEdge> p=DinicMainGraph.getPath(g3, v5, v4);
		double x=DinicMainGraph.getBottleN(p);
		assertTrue("bneck1", x==1);
	}
/*
	@Test
	public void testFlow() {
		
		try {
			g=new DinicMainGraph(gs,mg);
			g.flow(DinicMainGraph.getPath(g.getMaingraph(),g.getSource(), g.getSink()));
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");
		}
		
		
		assertNull(DinicMainGraph.getPath(g.getMaingraph(),g.getSource(), g.getSink()));
	}
*/
	@Test
	public void testLayered(){
		try {
			g=new DinicMainGraph(gs,mg);
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");	
		}
		try {
			DefaultDirectedWeightedGraph<Operator, FlowingEdge> a=g.getLayeredNetwork(g.getMaingraph(), g.getSource());
			
			
			assertTrue("number of edges",a.edgeSet().size()==3);
			assertTrue("number of vertexes",a.vertexSet().size()==4);
		
			
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");
		}
		
		
	}
	

	@Test
	public void testGetPath(){
		Vector<FlowingEdge> ans=DinicMainGraph.getPath(g3, v5, v4);
		assertTrue("ans size",ans.size()==2||ans.size()==3);
	}
	
	@Test
	public void testDinicFlow(){
		try {
			g=new DinicMainGraph(gs,mg);
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");	
		}
		try {
			g.dinicFlow();
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");
		}
		for (FlowingEdge i:g.getMaingraph().edgeSet()){
			if (g.getMaingraph().getEdgeSource(i)==o1 &&g.getMaingraph().getEdgeTarget(i)==o2)
				assertTrue("o1 o2",i.getFlow()==0);
			if (g.getMaingraph().getEdgeSource(i)==g.getSource() &&g.getMaingraph().getEdgeTarget(i)==o1)
				assertTrue("s o1",i.getFlow()==1);
			if (g.getMaingraph().getEdgeSource(i)==g.getSource() &&g.getMaingraph().getEdgeTarget(i)==o2)
				assertTrue("s o2",i.getFlow()==0);
			if (g.getMaingraph().getEdgeSource(i)==o1 &&g.getMaingraph().getEdgeTarget(i)==g.getSink())
				assertTrue("o1 sink",i.getFlow()==1);
		}
	}
	
	@Test
	public void testDinicFlow2(){
		Operator v1=new Operator("v1");
		Operator v2 = new Operator("v2");
		Operator s = new Operator("s");
		Operator t= new Operator("t");
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> g=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		g.addVertex(v1);
		g.addVertex(v2);
		g.addVertex(s);
		g.addVertex(t);
		FlowingEdge e=g.addEdge(s, v1);
		e.setCapacity(3);
		e=g.addEdge(s, v2);
		e.setCapacity(5);
		e=g.addEdge(v1, v2);
		e.setCapacity(3);
		e=g.addEdge( v2,v1);
		e.setCapacity(2);
		e=g.addEdge(v2,t);
		e.setCapacity(3);
		e=g.addEdge(v1,t);
		e.setCapacity(6);
		DinicMainGraph dg=new DinicMainGraph(g,s,t);
		try {
			dg.dinicFlow();
		} catch (Exception e1) {
			e1.printStackTrace();
			fail("exception happened");
		}
		
		
		
		for (FlowingEdge i:dg.getMaingraph().edgeSet()){
			if (dg.getMaingraph().getEdgeSource(i)==dg.getSource() &&dg.getMaingraph().getEdgeTarget(i)==v1)
				assertTrue("s v1",i.getFlow()==3);
			if (dg.getMaingraph().getEdgeSource(i)==dg.getSource() &&dg.getMaingraph().getEdgeTarget(i)==v2)
				assertTrue("s v2",i.getFlow()==5);
			if (dg.getMaingraph().getEdgeSource(i)==v1 &&dg.getMaingraph().getEdgeTarget(i)==v2)
				assertTrue("v1 v2",i.getFlow()==0);
			if (dg.getMaingraph().getEdgeSource(i)==v2 &&dg.getMaingraph().getEdgeTarget(i)==v1)
				assertTrue("v2 v1",i.getFlow()==2);
			if (dg.getMaingraph().getEdgeSource(i)==v2 &&dg.getMaingraph().getEdgeTarget(i)==dg.getSink())
				assertTrue("v2 t",i.getFlow()==3);
			if (dg.getMaingraph().getEdgeSource(i)==v1 &&dg.getMaingraph().getEdgeTarget(i)==dg.getSink())
				assertTrue("v2 t",i.getFlow()==5);
		}
		
	}
	
	
	@Test
	public void testMinCut(){
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> right=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> left=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> cut=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		try {
			g=new DinicMainGraph(gs,mg);
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");	
		}
		int ans=0;
		try {
			g.dinicFlow();
			ans=g.minCut(left,right,cut);
		} catch (Exception e) {
			e.printStackTrace();
			fail("exception happened");
		}
		
		assertTrue(left.vertexSet().contains(o2));
		assertTrue(right.vertexSet().contains(o1));
		assertTrue (ans==1);
		right=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		left=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		cut=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		Operator v1=new Operator("v1");
		Operator v2 = new Operator("v2");
		Operator s = new Operator("s");
		Operator t= new Operator("t");
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> g=new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		g.addVertex(v1);
		g.addVertex(v2);
		g.addVertex(s);
		g.addVertex(t);
		FlowingEdge e=g.addEdge(s, v1);
		e.setCapacity(3);
		e=g.addEdge(s, v2);
		e.setCapacity(5);
		e=g.addEdge(v1, v2);
		e.setCapacity(3);
		e=g.addEdge( v2,v1);
		e.setCapacity(2);
		e=g.addEdge(v2,t);
		e.setCapacity(3);
		e=g.addEdge(v1,t);
		e.setCapacity(6);
		DinicMainGraph dg=new DinicMainGraph(g,s,t);
		try {
			dg.dinicFlow();
			ans=dg.minCut(left,right,cut);
		} catch (Exception e2) {
			e2.printStackTrace();
			fail("exception happened");
		}
		assertTrue(right.vertexSet().contains(v1));
		assertTrue(right.vertexSet().contains(v2));
		assertTrue(right.vertexSet().contains(t));
		assertTrue(left.vertexSet().contains(s));
		assertTrue(ans==8);		
	}

}
